// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package x86

import (
	"cmd/internal/obj"
	"errors"
	"fmt"
	"strings"
)

// evexBits存储指令编码期间使用的EVEX前缀信息。
type evexBits struct {
	b1 byte // /[W1mmLLpp]

	// 相关指令操作码。
	opcode byte
}

// newEVEXBits从z位置的enc字节创建evexBits对象。
func newEVEXBits(z int, enc *opBytes) evexBits {
	return evexBits{
		b1:     enc[z+0],
		b2:     enc[z+1],
		opcode: enc[z+2],
	}
}

// P返回EVEX。pp值。
func (evex evexBits) P() byte { return (evex.b1 & evexP) >> 0 }

// L返回EVEX。我的价值观。
func (evex evexBits) L() byte { return (evex.b1 & evexL) >> 2 }

// M返回EVEX。毫米值。
func (evex evexBits) M() byte { return (evex.b1 & evexM) >> 4 }

// W返回EVEX。W值。
func (evex evexBits) W() byte { return (evex.b1 & evexW) >> 7 }

// BroadcastEnabled报告是否允许使用BCST后缀。
func (evex evexBits) BroadcastEnabled() bool {
	return evex.b2&evexBcst != 0
}

// ZeroInEnabled报告是否允许使用Z后缀。
func (evex evexBits) ZeroingEnabled() bool {
	return (evex.b2&evexZeroing)>>2 != 0
}

// 四舍五入报告RN_SAE、RZ_SAE、RD_SAE和RU_SAE后缀
// 是否允许。
func (evex evexBits) RoundingEnabled() bool {
	return (evex.b2&evexRounding)>>1 != 0
}

// SAEEEnabled报告是否允许使用SAE后缀。
func (evex evexBits) SaeEnabled() bool {
	return (evex.b2&evexSae)>>0 != 0
}

// DispMultiplier返回基于元组类型EVEX计算的位移乘数
// 。W和输入大小。
// 如果使用嵌入式广播，则bcst应为真。
func (evex evexBits) DispMultiplier(bcst bool) int32 {
	if bcst {
		switch evex.b2 & evexBcst {
		case evexBcstN4:
			return 4
		case evexBcstN8:
			return 8
		}
		return 1
	}

	switch evex.b2 & evexN {
	case evexN1:
		return 1
	case evexN2:
		return 2
	case evexN4:
		return 4
	case evexN8:
		return 8
	case evexN16:
		return 16
	case evexN32:
		return 32
	case evexN64:
		return 64
	case evexN128:
		return 128
	}
	return 1
}

// EVEX使用2字节序列描述。
// 有关更多详细信息，请参阅evexBits。
const (
	evexW   = 0x80 // b1[W….]
	evexWIG = 0 << 7
	evexW0  = 0 << 7
	evexW1  = 1 << 7

	evexM    = 0x30 // b2[…毫米…]
	evex0F   = 1 << 4
	evex0F38 = 2 << 4
	evex0F3A = 3 << 4

	evexL   = 0x0C // b1[..LL..]
	evexLIG = 0 << 2
	evex128 = 0 << 2
	evex256 = 1 << 2
	evex512 = 2 << 2

	evexP  = 0x03 // b1[……pp]
	evex66 = 1 << 0
	evexF3 = 2 << 0
	evexF2 = 3 << 0

	// /预先计算的显示值。
	// N相当于8位置换的乘数。
	// 请注意，有些N没有使用，但它们的位是保留的。
	evexN    = 0xE0 // b2[NNN….]
	evexN1   = 0 << 5
	evexN2   = 1 << 5
	evexN4   = 2 << 5
	evexN8   = 3 << 5
	evexN16  = 4 << 5
	evexN32  = 5 << 5
	evexN64  = 6 << 5
	evexN128 = 7 << 5

	// Disp8用于广播。
	evexBcst   = 0x18 // b2[…b….]
	evexBcstN4 = 1 << 3
	evexBcstN8 = 2 << 3

	// 允许某些AVX512功能的标志。
	// 结合evexzeroning和evexSae在语义上是非法的。
	evexZeroing         = 0x4 // b2[
	evexZeroingEnabled  = 1 << 2
	evexRounding        = 0x2 // b2[..R.]
	evexRoundingEnabled = 1 << 1
	evexSae             = 0x1 // b2[..S]
	evexSaeEnabled      = 1 << 0
)

// CompressedDSP8计算EVEX压缩位移（如适用）。
func compressedDisp8(disp, elemSize int32) (disp8 byte, ok bool) {
	if disp%elemSize == 0 {
		v := disp / elemSize
		if v >= -128 && v <= 127 {
			return byte(v), true
		}
	}
	return 0, false
}

// evexZcase报告给定的Z病例是否属于EVEX组。
func evexZcase(zcase uint8) bool {
	return zcase > Zevex_first && zcase < Zevex_last
}

// evexSuffixBits携带指令EVEX后缀集标志。
// 
// 示例：
// /“RU_SAE.Z”=>{舍入：3，归零：真}。
type evexSuffix struct {
	rounding  byte
	sae       bool
	zeroing   bool
	broadcast bool
}

// 匹配EVEX的精确值。L'L字段（rcUnset除外）。
const (
	rcRNSAE = 0 // 向最近的
	rcRDSAE = 1 // 向-Inf 
	rcRUSAE = 2 // 向+Inf 
	rcRZSAE = 3 // 向零
	rcUnset = 4
)

// newEVEXSuffix为evexSuffix返回正确的零值。
func newEVEXSuffix() evexSuffix {
	return evexSuffix{rounding: rcUnset}
}

// evexSuffixMap映射对象。将x86后缀添加到其解码版本。
// 在初始化期间填充（）。
var evexSuffixMap [255]evexSuffix

func init() {
	// 对所有有效后缀进行解码，以备日后使用。
	for i := range opSuffixTable {
		suffix := newEVEXSuffix()
		parts := strings.Split(opSuffixTable[i], ".")
		for j := range parts {
			switch parts[j] {
			case "Z":
				suffix.zeroing = true
			case "BCST":
				suffix.broadcast = true
			case "SAE":
				suffix.sae = true

			case "RN_SAE":
				suffix.rounding = rcRNSAE
			case "RD_SAE":
				suffix.rounding = rcRDSAE
			case "RU_SAE":
				suffix.rounding = rcRUSAE
			case "RZ_SAE":
				suffix.rounding = rcRZSAE
			}
		}
		evexSuffixMap[i] = suffix
	}
}

// toDisp8尝试将disp转换为正确的8位位移值。
func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) {
	if asmbuf.evexflag {
		bcst := evexSuffixMap[p.Scond].broadcast
		elemSize := asmbuf.evex.DispMultiplier(bcst)
		return compressedDisp8(disp, elemSize)
	}
	return byte(disp), disp >= -128 && disp < 128
}

// EncodeRegisterRange将[reg0-reg1]列表打包为64位值，
// 将存储在obj中。地址。用类型_REGLIST进行偏移。
func EncodeRegisterRange(reg0, reg1 int16) int64 {
	return (int64(reg0) << 0) |
		(int64(reg1) << 16) |
		obj.RegListX86Lo
}

// DecodeRegistrange从EncodeRegistrange创建的64位值中解压[reg0-reg1]列表。
func decodeRegisterRange(list int64) (reg0, reg1 int) {
	return int((list >> 0) & 0xFFFF),
		int((list >> 16) & 0xFFFF)
}

// ParseSuffix处理386/AMD64的特殊后缀。
// 后缀位存储在p.Scond中。
// 
// 前导“in cond被忽略。
func ParseSuffix(p *obj.Prog, cond string) error {
	cond = strings.TrimPrefix(cond, ".")

	suffix := newOpSuffix(cond)
	if !suffix.IsValid() {
		return inferSuffixError(cond)
	}

	p.Scond = uint8(suffix)
	return nil
}

// InferreSuffixerror返回非零错误，描述后缀解析失败的原因。
// 
// 在执行此函数时，已经存在汇编错误，
// 因此我们可以烧掉一些时钟来构造良好的错误消息。
// 
// 报告问题：
// -重复后缀
// -非法舍入/SAE+广播组合
// -未知后缀
// -错误后缀（例如错误的Z后缀位置）
func inferSuffixError(cond string) error {
	suffixSet := make(map[string]bool)  // /设置为重复检测。
	unknownSet := make(map[string]bool) // 一组未知后缀。
	hasBcst := false
	hasRoundSae := false
	var msg []string // 错误消息部分

	suffixes := strings.Split(cond, ".")
	for i, suffix := range suffixes {
		switch suffix {
		case "Z":
			if i != len(suffixes)-1 {
				msg = append(msg, "Z suffix should be the last")
			}
		case "BCST":
			hasBcst = true
		case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE":
			hasRoundSae = true
		default:
			if !unknownSet[suffix] {
				msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix))
			}
			unknownSet[suffix] = true
		}

		if suffixSet[suffix] {
			msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix))
		}
		suffixSet[suffix] = true
	}

	if hasBcst && hasRoundSae {
		msg = append(msg, "can't combine rounding/SAE and broadcast")
	}

	if len(msg) == 0 {
		return errors.New("bad suffix combination")
	}
	return errors.New(strings.Join(msg, "; "))
}

// OPSUFFEXTABLE是可能的操作码后缀组合的完整列表。
// 它将uint8后缀位“映射”到它们的字符串表示形式。
// 除了第一个和最后一个元素，顺序并不重要。
var opSuffixTable = [...]string{
	"", // 将空后缀映射到空字符串。

	"Z",

	"SAE",
	"SAE.Z",

	"RN_SAE",
	"RZ_SAE",
	"RD_SAE",
	"RU_SAE",
	"RN_SAE.Z",
	"RZ_SAE.Z",
	"RD_SAE.Z",
	"RU_SAE.Z",

	"BCST",
	"BCST.Z",

	"<bad suffix>",
}

// opSuffix表示指令操作码后缀。
// 复合（多部分）后缀，用单个opSuffix值表示。
// 
// uint8型用于安装obj。掠夺。斯科德。
type opSuffix uint8

// badOpSuffix用于表示所有无效的后缀组合。
const badOpSuffix = opSuffix(len(opSuffixTable) - 1)

// newOpSuffix返回与后缀字符串匹配的opSuffix对象。
// 
// 如果没有找到匹配的后缀，则返回特殊的“无效”后缀。
// 使用IsValid方法检查此案例。
func newOpSuffix(suffixes string) opSuffix {
	for i := range opSuffixTable {
		if opSuffixTable[i] == suffixes {
			return opSuffix(i)
		}
	}
	return badOpSuffix
}

// IsValid报告后缀是否有效。
// 空后缀有效。
func (suffix opSuffix) IsValid() bool {
	return suffix != badOpSuffix
}

// 字符串返回后缀打印的表示形式。
// 
// 它与用于创建后缀的字符串相匹配，使用NewX86Suffix（）
// 表示有效后缀。
// 对于所有无效后缀，返回特殊标记。
func (suffix opSuffix) String() string {
	return opSuffixTable[suffix]
}
